home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 5 / Skunkware 5.iso / src / X11 / xpaint-2.1.1 / palette.c < prev    next >
C/C++ Source or Header  |  1995-05-03  |  16KB  |  712 lines

  1. /* +-------------------------------------------------------------------+ */
  2. /* | Copyright 1992, 1993, David Koblas (koblas@netcom.com)            | */
  3. /* |                                                                   | */
  4. /* | Permission to use, copy, modify, and to distribute this software  | */
  5. /* | and its documentation for any purpose is hereby granted without   | */
  6. /* | fee, provided that the above copyright notice appear in all       | */
  7. /* | copies and that both that copyright notice and this permission    | */
  8. /* | notice appear in supporting documentation.  There is no           | */
  9. /* | representations about the suitability of this software for        | */
  10. /* | any purpose.  this software is provided "as is" without express   | */
  11. /* | or implied warranty.                                              | */
  12. /* |                                                                   | */
  13. /* +-------------------------------------------------------------------+ */
  14.  
  15. #include <X11/Intrinsic.h>
  16. #include <X11/StringDefs.h>
  17. #include <X11/Shell.h>
  18. #include <X11/Xatom.h>
  19. #include <stdio.h>
  20. #include "palette.h"
  21. #include "hash.h"
  22. #include "misc.h"
  23. #include "image.h"
  24. #include "xpaint.h"
  25.  
  26. typedef struct list_s {
  27.     Display        *dpy;
  28.     Colormap    cmap;
  29.     Palette        *map;
  30.     struct list_s    *next;
  31. } PaletteList;
  32.  
  33. typedef struct Col_s {
  34.     XColor        color;
  35.     Boolean        used;
  36.     Boolean        invalid;
  37. } Col;
  38.  
  39. #define HASH_SIZE 128
  40. #define HASH(c)         ((int)((c).red + (c).green + (c).blue) % HASH_SIZE)
  41. #define HASH_PIXEL(c)     (c % HASH_SIZE)
  42.  
  43. static PaletteList    *cmapList = NULL;
  44.  
  45. static int      readCMP(Col *cca, Col *ccb)
  46. {
  47.     XColor    *ca = &cca->color, *cb = &ccb->color;
  48.  
  49.     if (ca->red != cb->red)
  50.         return ca->red < cb->red ? -1 : 1;
  51.     if (ca->green != cb->green)
  52.         return ca->green < cb->green ? -1 : 1;
  53.     if (ca->blue != cb->blue)
  54.         return ca->blue < cb->blue ? -1 : 1;
  55.         return 0;
  56. }
  57.  
  58. static int      cmpPixel(Col *cca, Col *ccb)
  59. {
  60.     if (cca->color.pixel == ccb->color.pixel)
  61.         return 0;
  62.     return (cca->color.pixel < ccb->color.pixel) ? -1 : 1;
  63. }
  64.  
  65. static void    freeFunc(void *junk)
  66. {
  67.     /*
  68.     **  Nop free func
  69.     */
  70. }
  71.  
  72. static void    entryUnlink(Palette *map, Col *node)
  73. {
  74.     node->used    = True;
  75.     node->invalid = False;
  76.     map->nfree--;
  77. }
  78.  
  79.  
  80. #define STEP    256
  81.  
  82. static Palette *paletteNew(Widget w, Boolean useDefault)
  83. {
  84.     int            i, v;
  85.     Display            *dpy = XtDisplay(w);
  86.     Screen            *screen = XtScreen(w);
  87.     Colormap        rcmap = DefaultColormapOfScreen(screen);
  88.     Palette            *map = XtNew(Palette);
  89.     Col            *ctable;
  90.     Visual            *visual = NULL;
  91.     PaletteList        *new;
  92.     int            end, depth = -1;
  93.     Boolean            flg = False;
  94.  
  95.     XtVaGetValues(w, XtNvisual, &visual, XtNdepth, &depth, NULL);
  96.     if (visual == NULL || useDefault)
  97.         visual = DefaultVisualOfScreen(screen);
  98.     if (depth <= 0 || useDefault)
  99.         depth = DefaultDepthOfScreen(screen);
  100.  
  101.     map->htable  = NULL;
  102.     map->ltable  = NULL;
  103.     map->display = dpy;
  104.     map->htable  = HashCreate(readCMP,  freeFunc, HASH_SIZE);
  105.     map->ltable  = HashCreate(cmpPixel, freeFunc, HASH_SIZE);
  106.     map->list    = NULL;
  107.     map->last    = NULL;
  108.     map->isMapped= visual->class != TrueColor;
  109.     map->isGrey  = (visual->class == StaticGray || visual->class == GrayScale);
  110.     map->ncolors = visual->map_entries;
  111.     map->nfree   = 0;
  112.     map->ctable  = NULL;
  113.     map->visual  = visual;
  114.     map->depth   = depth;
  115.     map->userList = NULL;
  116.     map->isDefault = False;
  117.     map->mine    = None;
  118.  
  119.     switch (visual->class) {
  120.     case TrueColor:
  121.         map->rShift = 0;
  122.         map->gShift = 0;
  123.         map->bShift = 0;
  124.         map->rRange = 1;
  125.         map->gRange = 1;
  126.         map->bRange = 1;
  127.         for (v = visual->red_mask; (v & 1) == 0; v >>= 1)
  128.             map->rShift++;
  129.         for (; (v & 1) == 1; v >>= 1)
  130.             map->rRange <<= 1;
  131.         for (v = visual->green_mask; (v & 1) == 0; v >>= 1)
  132.             map->gShift++;
  133.         for (; (v & 1) == 1; v >>= 1)
  134.             map->gRange <<= 1;
  135.         for (v = visual->blue_mask; (v & 1) == 0; v >>= 1)
  136.             map->bShift++;
  137.         for (; (v & 1) == 1; v >>= 1)
  138.             map->bRange <<= 1;
  139.     case StaticGray:
  140.     case StaticColor:
  141.         map->readonly  = True;
  142.         map->cmap = XCreateColormap(dpy, RootWindowOfScreen(screen), 
  143.                         visual, AllocNone);
  144.         map->isDefault = False;
  145.         goto addlist;
  146.     default:
  147.         map->readonly = False;
  148.         if (useDefault) {
  149.             map->cmap = rcmap;
  150.             map->isDefault = True;
  151.         } else {
  152.             map->cmap = XCreateColormap(dpy, RootWindowOfScreen(screen), 
  153.                         visual, AllocAll);
  154.         }
  155.         break;
  156.     }
  157.  
  158.     ctable = (Col *)XtCalloc(sizeof(Col), visual->map_entries);
  159.     map->ctable = ctable;
  160.     end = CellsOfScreen(screen);
  161.     for (i = 0; i < visual->map_entries; i += STEP) {
  162.         XColor    xcol[STEP];
  163.         int    cnt = visual->map_entries - i;
  164.         int    j, d;
  165.  
  166.         if (cnt > STEP)
  167.             cnt = STEP;
  168.  
  169.         for (j = 0; j < cnt; j++) {
  170.             Col    *c = &ctable[i + j];
  171.  
  172.             c->color.pixel = i + j;
  173.             c->color.flags = DoRed|DoGreen|DoBlue;
  174.             xcol[j].pixel = i + j;
  175.             xcol[j].flags = DoRed|DoGreen|DoBlue;
  176.  
  177.             c->used    = False;
  178.             c->invalid = False;
  179.         }
  180.  
  181.         if (i >= end)
  182.             d = 0;
  183.         else    
  184.             d = MIN(end - i, cnt);
  185.  
  186.         if (i < end)
  187.             XQueryColors(dpy, rcmap, xcol, d);
  188.         if (!flg) {
  189.             for (j = d; j < cnt; j++) {
  190.                 xcol[j].flags = DoRed|DoGreen|DoBlue;
  191.                 xcol[j].red = xcol[j].green = xcol[j].blue = 0xffff;
  192.             }
  193.             if (d == 0)
  194.                 flg = True;
  195.         }
  196.  
  197.         if (!map->isDefault)
  198.             XStoreColors(dpy, map->cmap, xcol, cnt);
  199.  
  200.         for (j = 0; j < cnt; j++) {
  201.             Col        *c = &ctable[i + j];
  202.  
  203.             c->color.red   = xcol[j].red & 0xff00;
  204.             c->color.green = xcol[j].green & 0xff00;
  205.             c->color.blue  = xcol[j].blue & 0xff00;
  206.             HashAdd(map->htable, HASH(c->color), c);
  207.             HashAdd(map->ltable, HASH_PIXEL(c->color.pixel), c);
  208.         }
  209.     }
  210.  
  211.     map->nfree = visual->map_entries;
  212.  
  213.     if (!map->isDefault) {
  214.         Boolean        got = False;
  215.  
  216.         got = !map->isMapped;
  217.         for (i = 0; i < visual->map_entries; i++) {
  218.             if (ctable[i].color.pixel == BlackPixelOfScreen(screen)) {
  219.                 entryUnlink(map, &ctable[i]);
  220.             } else if (ctable[i].color.pixel == WhitePixelOfScreen(screen)) {
  221.                 entryUnlink(map, &ctable[i]);
  222.             } else if (!got) {
  223.                 map->mine = i;
  224.                 entryUnlink(map, &ctable[i]);
  225.                 got = True;
  226.             }
  227.         }
  228.     }
  229.  
  230. addlist:
  231.     new = (PaletteList*)XtMalloc(sizeof(PaletteList));
  232.     new->dpy     = XtDisplay(w);
  233.     new->cmap    = map->cmap;
  234.     new->next    = cmapList;
  235.     new->map     = map;
  236.     cmapList     = new;
  237.  
  238.     return map;
  239. }
  240.  
  241. Palette *PaletteCreate(Widget w)
  242. {
  243.     return paletteNew(GetShell(w), False);
  244. }
  245.  
  246. Palette *PaletteGetDefault(Widget w)
  247. {
  248.     static Palette    *defMap = NULL;
  249.  
  250.     if (defMap == NULL)
  251.         defMap = paletteNew(GetShell(w), True);
  252.  
  253.     return defMap;
  254. }
  255. static Palette *paletteGetBW()
  256. {
  257.     static Palette    *map = NULL;
  258.     XColor        xcol;
  259.     Col        *ctable;
  260.  
  261.     if (map != NULL)
  262.         return map;
  263.  
  264.     map = XtNew(Palette);
  265.     
  266.     map->display = NULL;
  267.     map->htable  = HashCreate(readCMP,  freeFunc, HASH_SIZE);
  268.     map->ltable  = HashCreate(cmpPixel, freeFunc, HASH_SIZE);
  269.     map->list    = NULL;
  270.     map->last    = NULL;
  271.     map->isMapped= True;
  272.     map->isGrey  = True;
  273.     map->ncolors = 2;
  274.     map->nfree   = 0;
  275.     map->ctable  = NULL;
  276.     map->visual  = None;    /* X */
  277.     map->depth   = 1;
  278.     map->userList= NULL;
  279.     map->isDefault= False;
  280.     map->mine    = None;
  281.     map->cmap    = None;
  282.  
  283.     ctable = (Col *)XtCalloc(sizeof(Col), map->ncolors);
  284.     map->ctable = ctable;
  285.  
  286.     ctable[0].color.pixel = 0;
  287.     ctable[0].color.flags = DoRed|DoGreen|DoBlue;
  288.     ctable[0].color.red   = 0xffff;
  289.     ctable[0].color.green = 0xffff;
  290.     ctable[0].color.blue  = 0xffff;
  291.     ctable[0].used        = True;
  292.     ctable[0].invalid     = False;
  293.  
  294.     ctable[1].color.pixel = 1;
  295.     ctable[1].color.flags = DoRed|DoGreen|DoBlue;
  296.     ctable[1].color.red   = 0x0000;
  297.     ctable[1].color.green = 0x0000;
  298.     ctable[1].color.blue  = 0x0000;
  299.     ctable[1].used        = True;
  300.     ctable[1].invalid     = False;
  301.  
  302.     HashAdd(map->htable, HASH(ctable[0].color), &ctable[0]);
  303.     HashAdd(map->htable, HASH(ctable[1].color), &ctable[1]);
  304.     HashAdd(map->ltable, HASH_PIXEL(ctable[0].color.pixel), &ctable[0]);
  305.     HashAdd(map->ltable, HASH_PIXEL(ctable[1].color.pixel), &ctable[1]);
  306.  
  307.     return map;
  308. }
  309.  
  310. static void addColor(Palette *map, XColor *color)
  311. {
  312.     Col    *node, *n;
  313.     int    i;
  314.  
  315.     if (map->readonly) {
  316.         /*
  317.         **  The temporary color is needed since alloc
  318.         **  will change the pixel values.
  319.         */
  320.         XColor    newc;
  321.         newc = *color;
  322.         node = XtNew(Col);
  323.  
  324.         newc.flags = DoRed|DoGreen|DoBlue;
  325.         XAllocColor(map->display, map->cmap, &newc);
  326.         node->color.pixel = color->pixel = newc.pixel;
  327.     } else {
  328.         Col        *cptr = (Col*)map->ctable;
  329.         int        d, curDif = -1;
  330.         int        rd, gd, bd;
  331.  
  332.         /*
  333.         **  Find the closest match in the existing color map.
  334.         */
  335.         node = cptr;
  336.  
  337.         for (i = 0; i < map->ncolors; i++, cptr++) {
  338.             if (map->nfree != 0 && cptr->used)
  339.                 continue;
  340.  
  341.             rd = (cptr->color.red >> 8)   - (color->red >> 8);
  342.             gd = (cptr->color.green >> 8) - (color->green >> 8);
  343.             bd = (cptr->color.blue >> 8)  - (color->blue >> 8);
  344.             d  = rd * rd + gd * gd + bd * bd;
  345.  
  346.             if (d < curDif || curDif == -1) {
  347.                 node   = cptr;
  348.                 curDif = d;
  349.             }
  350.         }
  351.  
  352.         /*
  353.         **  All free colors used up.
  354.         */
  355.         if (map->nfree == 0) {
  356.             color->pixel = node->color.pixel;
  357.             return;
  358.         }
  359.  
  360.         /*
  361.         **  Get next free color.
  362.         */
  363.         entryUnlink(map, node);
  364.  
  365.         n = HashFind(map->ltable, HASH_PIXEL(node->color.pixel), node);
  366.         HashRemove(map->ltable, HASH_PIXEL(color->pixel), n);
  367.         HashRemove(map->htable, HASH(*color), node);
  368.  
  369.         color->pixel = node->color.pixel;
  370.     }
  371.  
  372.     node->used        = True;
  373.     node->invalid     = False;
  374.     node->color.red   = color->red   & 0xff00;
  375.     node->color.green = color->green & 0xff00;
  376.     node->color.blue  = color->blue  & 0xff00;
  377.     node->color.flags = DoRed|DoGreen|DoBlue;
  378.     if (!map->readonly)
  379.         XStoreColor(map->display, map->cmap, &node->color);
  380.     HashAdd(map->htable, HASH(*color), node);
  381.     HashAdd(map->ltable, HASH_PIXEL(color->pixel), node);
  382. }
  383.  
  384. static Col *allocN(Palette *map, int ncolor, Boolean *flags, XColor *colors, Pixel *list)
  385. {
  386.     Col    c, *node = NULL;
  387.     int    i;
  388.  
  389.     for (i = 0; i < ncolor; i++) {
  390.         if (flags != NULL && flags[i])
  391.             continue;
  392.  
  393.         c.color.red   = colors[i].red   & 0xff00;
  394.         c.color.green = colors[i].green & 0xff00;
  395.         c.color.blue  = colors[i].blue  & 0xff00;
  396.  
  397.         if ((node = HashFind(map->htable, HASH(c.color), &c)) == NULL) {
  398.             addColor(map, &colors[i]);
  399.             list[i] = colors[i].pixel;
  400.         } else {
  401.             /*
  402.             **  It must have been allocated in the previous
  403.             **   pass, or by the above.
  404.             */
  405.             if (!node->used) 
  406.                 entryUnlink(map, node);
  407.             list[i] = node->color.pixel;
  408.         }
  409.     }
  410.  
  411.     return node;
  412. }
  413.  
  414. int PaletteAllocN(Palette *map, XColor *color, int ncolor, Pixel *list)
  415. {
  416.     Boolean    *flg = XtCalloc(sizeof(Boolean), ncolor);
  417.     Col    c, *node;
  418.     int    i;
  419.     Boolean    newMine = False;
  420.  
  421.     if (!map->isMapped) {
  422.         for (i = 0; i < ncolor; i++) {
  423.             unsigned int    r, g, b;
  424.  
  425.             r = (color[i].red   * map->rRange) >> 16;
  426.             g = (color[i].green * map->gRange) >> 16;
  427.             b = (color[i].blue  * map->bRange) >> 16;
  428.             list[i] = (r << map->rShift)|(g << map->gShift)|(b << map->bShift);
  429.         }
  430.         return 0;
  431.     }
  432.  
  433.     for (i = 0; i < ncolor; i++) {
  434.         Col    c;
  435.  
  436.         c.color.red   = color[i].red   & 0xff00;
  437.         c.color.green = color[i].green & 0xff00;
  438.         c.color.blue  = color[i].blue  & 0xff00;
  439.  
  440.         if ((node = HashFind(map->htable, HASH(c.color), &c)) != NULL) {
  441.             flg[i] = True;
  442.             /*
  443.             **  Match found, if the entry hasn't been "alloced"
  444.             **   yet, mark it so, and remove it from the "free" list.
  445.             */
  446.             if (!node->used) 
  447.                 entryUnlink(map, node);
  448.             list[i] = node->color.pixel;
  449.             if (list[i] == map->mine)
  450.                 newMine = True;
  451.         } else {
  452.             flg[i] = False;
  453.         }
  454.     }
  455.  
  456.     for (i = 0; i < ncolor; i++) {
  457.         if (flg[i])
  458.             continue;
  459.  
  460.         c.color.red   = color[i].red   & 0xff00;
  461.         c.color.green = color[i].green & 0xff00;
  462.         c.color.blue  = color[i].blue  & 0xff00;
  463.  
  464.         if ((node = HashFind(map->htable, HASH(c.color), &c)) == NULL) {
  465.             addColor(map, &color[i]);
  466.             list[i] = color[i].pixel;
  467.         } else {
  468.             /*
  469.             **  It must have been allocated in the previous
  470.             **   pass, or by the above.
  471.             */
  472.             list[i] = node->color.pixel;
  473.         }
  474.         if (list[i] == map->mine)
  475.             newMine = True;
  476.     }
  477.  
  478.     XtFree((XtPointer)flg);
  479.  
  480.     if (newMine && map->ctable != NULL) {
  481.         Col             *cptr = (Col*)map->ctable;
  482.  
  483.         for (i = 0; i < map->ncolors; i++, cptr++) {
  484.             if (cptr->used)
  485.                 continue;
  486.             map->mine = cptr->color.pixel;
  487.             break;
  488.         }
  489.     }
  490.  
  491.     return 0;
  492. }
  493.  
  494. Pixel PaletteAlloc(Palette *map, XColor *color)
  495. {
  496.     if (!map->isMapped) {
  497.         unsigned int    r, g, b;
  498.  
  499.         r = (color->red   * map->rRange) >> 16;
  500.         g = (color->green * map->gRange) >> 16;
  501.         b = (color->blue  * map->bRange) >> 16;
  502.         return (r << map->rShift)|(g << map->gShift)|(b << map->bShift);
  503.     }
  504.  
  505.     if (map->last != NULL) {
  506.         XColor    *lc = (XColor*)map->last;
  507.  
  508.         if (lc->red   == color->red && 
  509.             lc->green == color->green &&
  510.             lc->blue  == color->blue) 
  511.             return color->pixel = lc->pixel;
  512.     }
  513.  
  514.     map->last = allocN(map, 1, NULL, color, &color->pixel);
  515.  
  516.     return color->pixel;
  517. }
  518.  
  519. /*
  520. **  Given a Pixel value on the specified map return the
  521. **   RGV value.
  522. **
  523. **   Special case "TrueColor" since it is just computed.
  524. **
  525. */
  526. XColor *PaletteLookup(Palette *map, Pixel pix)
  527. {
  528.     if (map->isMapped) {
  529.         Col    col;
  530.         Col    *c;
  531.  
  532.         col.color.pixel = pix;
  533.  
  534.         if ((c = (Col*)HashFind(map->ltable, HASH_PIXEL(pix), &col)) == NULL) {
  535.             printf("Shouldn't happen\n");
  536.             return NULL;
  537.         }
  538.  
  539.         if (c->invalid) {
  540.             HashRemove(map->htable, HASH(c->color), c);
  541.             XQueryColor(map->display, map->cmap, &c->color);
  542.             c->color.red   &= 0xff00;
  543.             c->color.green &= 0xff00;
  544.             c->color.blue  &= 0xff00;
  545.             HashAdd(map->htable, HASH(c->color), c);
  546.             c->invalid = False;
  547.         }
  548.  
  549.         return &c->color;
  550.     } else {
  551.         static XColor    xc;
  552.  
  553.         xc.red   = (pix >> map->rShift) & (map->rRange-1);
  554.         xc.green = (pix >> map->gShift) & (map->gRange-1);
  555.         xc.blue  = (pix >> map->bShift) & (map->bRange-1);
  556.  
  557.         xc.red   *= 65536 / map->rRange;
  558.         xc.green *= 65536 / map->gRange;
  559.         xc.blue  *= 65536 / map->bRange;
  560.  
  561.         return &xc;
  562.     }
  563. }
  564.  
  565. Boolean PaletteLookupColor(Palette *map, XColor *col, Pixel *pxl)
  566. {
  567.     Col    c, *node;
  568.  
  569.     if (!map->isMapped) {
  570.         unsigned int    r, g, b;
  571.  
  572.         r = (col->red   * map->rRange) >> 16;
  573.         g = (col->green * map->gRange) >> 16;
  574.         b = (col->blue  * map->bRange) >> 16;
  575.         *pxl = (r << map->rShift)|(g << map->gShift)|(b << map->bShift);
  576.         return True;
  577.     }
  578.  
  579.     c.color.red   = col->red   & 0xff00;
  580.     c.color.green = col->green & 0xff00;
  581.     c.color.blue  = col->blue  & 0xff00;
  582.  
  583.     if ((node = HashFind(map->htable, HASH(c.color), &c)) != NULL) {
  584.         *pxl = node->color.pixel;
  585.         return True;
  586.     }
  587.  
  588.     return False;
  589. }
  590.  
  591. Pixel    PaletteGetUnused(Palette *map)
  592. {
  593.     return map->mine;
  594. }
  595.  
  596. /*
  597. **  Change the RGB value of a pixel
  598. */
  599. void PaletteSetInvalid(Palette *map, Pixel pix)
  600. {
  601.     Col    col, *c;
  602.  
  603.     if (!map->isMapped || map->readonly)
  604.         return;
  605.  
  606.     col.color.pixel = pix;
  607.  
  608.     if ((c = (Col*)HashFind(map->ltable, HASH_PIXEL(pix), &col)) == NULL)
  609.         return;
  610.  
  611.     c->invalid = True;
  612. }
  613.  
  614. /*
  615. **  This will fail if on a read only colormap
  616. */
  617. Boolean PaletteSetPixel(Palette *map, Pixel pixel, XColor *xcol)
  618. {
  619.     Col    col, *c;
  620.  
  621.     if (map->readonly)
  622.         return False;
  623.  
  624.     if (map->isDefault)
  625.         return False;
  626.     
  627.     xcol->pixel = pixel;
  628.     xcol->flags = DoRed|DoGreen|DoBlue;
  629.     XStoreColor(map->display, map->cmap, xcol);
  630.  
  631.     col.color.pixel = pixel;
  632.  
  633.     if ((c = (Col*)HashFind(map->ltable, HASH_PIXEL(pixel), &col)) != NULL)
  634.         c->invalid = True;
  635.  
  636.     return True;
  637. }
  638.  
  639. Palette *PaletteFindDpy(Display *dpy, Colormap cmap)
  640. {
  641.     PaletteList    *cur;
  642.  
  643.     if (cmap == -1)
  644.         return paletteGetBW();
  645.  
  646.     for (cur = cmapList; cur != NULL; cur = cur->next)
  647.         if (cur->cmap == cmap && cur->dpy == dpy)
  648.             return cur->map;
  649.  
  650.     return NULL;
  651. }
  652.  
  653. Palette *PaletteFind(Widget w, Colormap cmap)
  654. {
  655.     return PaletteFindDpy(XtDisplay(w), cmap);
  656. }
  657.  
  658. static void paletteAddUserDestroy(Widget w, Palette *map, XtPointer junk)
  659. {
  660.     paletteUserList    *cur = map->userList;
  661.     paletteUserList    **prev = &map->userList;
  662.  
  663.     while (cur != NULL && cur->widget != w) {
  664.         prev = &cur->next;
  665.         cur = cur->next;
  666.     }
  667.  
  668.     if (cur == NULL)
  669.         return;
  670.     
  671.     *prev = cur->next;
  672.     XtFree((XtPointer)cur);
  673. }
  674.  
  675. void PaletteDelete(Palette *map)
  676. {
  677.     PaletteList    *cur, **prev;
  678.     paletteUserList    *ul, *nx;
  679.  
  680.     HashDestroy(map->htable);
  681.     HashDestroy(map->ltable);
  682.     if (map->ctable != NULL)
  683.         XtFree((XtPointer)map->ctable);
  684.  
  685.     for (cur = cmapList, prev = &cmapList; cur != NULL && cur->map != map; 
  686.             prev = &cur->next, cur = cur->next);
  687.  
  688.     if (cur != NULL)
  689.         *prev = cur->next;
  690.         
  691.     ul = map->userList;
  692.     while (ul != NULL) {
  693.         nx = ul->next;
  694.         XtRemoveCallback(ul->widget, XtNdestroyCallback, (XtCallbackProc)paletteAddUserDestroy, (XtPointer)map);
  695.         XtFree((XtPointer)ul);
  696.         ul = nx;
  697.     }
  698.  
  699.     XtFree((XtPointer)map);
  700.     XtFree((XtPointer)cur);
  701. }
  702.  
  703. void PaletteAddUser(Palette *map, Widget w)
  704. {
  705.     paletteUserList    *n = XtNew(paletteUserList);
  706.  
  707.     n->widget = w;
  708.     n->next = map->userList;
  709.     map->userList = n;
  710.     XtAddCallback(w, XtNdestroyCallback, (XtCallbackProc)paletteAddUserDestroy, (XtPointer)map);
  711. }
  712.